#if !defined(__CL_ENABLE_EXCEPTIONS)
#define __CL_ENABLE_EXCEPTIONS
#endif

#include "DeviceInfo.hpp"
#include "cl.hpp"
#include <sstream>
#include <iostream>
#include <locale>

using namespace cl;

DeviceInfo::DeviceInfo(const Device &device) {
    std::stringstream ss;
    ss.imbue(std::locale(""));
    std::vector<std::size_t> maxWorkItemSizes;
    try {
        std:: string s = device.getInfo<CL_DEVICE_NAME>();
        name = s.substr(s.find_first_not_of(" \t")); // Remove leading spaces.
        hardwareVersion = device.getInfo<CL_DEVICE_VERSION>();
        softwareVersion = device.getInfo<CL_DRIVER_VERSION>();
        device.getInfo<std::string>(CL_DEVICE_OPENCL_C_VERSION, &openCLCVersion);
        ss << device.getInfo<CL_DEVICE_MAX_COMPUTE_UNITS>();
        computeUnits = ss.str(); ss.str("");
        ss << device.getInfo<CL_DEVICE_GLOBAL_MEM_CACHE_SIZE>() << " bytes";
        cacheSize = ss.str(); ss.str("");
        ss << device.getInfo<CL_DEVICE_MAX_CLOCK_FREQUENCY>() << " MHz";
        baseClockFrequency = ss.str(); ss.str("");
        ss << device.getInfo<CL_DEVICE_GLOBAL_MEM_SIZE>() << " bytes";
        memorySize = ss.str(); ss.str("");
        extensions = device.getInfo<CL_DEVICE_EXTENSIONS>();
        ss << "(";
        maxWorkItemSizes = device.getInfo<CL_DEVICE_MAX_WORK_ITEM_SIZES>();
        std::size_t size = maxWorkItemSizes.size();
        for(std::size_t i=0; i<size; i++) {
            ss << maxWorkItemSizes[i];
            if(i < size-1)
                ss << ", ";
        }
        ss << ")";
        maximumWorkItemsPerWorkGroup = ss.str(); ss.str("");
        ss << device.getInfo<CL_DEVICE_MAX_WORK_GROUP_SIZE>();
        maximumWorkGroupSize = ss.str(); ss.str("");
    } catch(Error &e) {
        std::cerr << "cl::DeviceInfo::DeviceInfo " <<
                     e.what() << "(" << e.err() << ")" << std::endl;
    }
}

const char *DeviceInfo::getName(void) const {
    return name.c_str();
}

const char *DeviceInfo::getHardwareVersion(void) const {
    return hardwareVersion.c_str();
}

const char *DeviceInfo::getSoftwareVersion(void) const {
    return softwareVersion.c_str();
}

const char *DeviceInfo::getOpenCLCVersion(void) const {
    return openCLCVersion.c_str();
}

const char *DeviceInfo::getComputeUnits(void) const {
    return computeUnits.c_str();
}

const char *DeviceInfo::getCacheSize(void) const {
    return cacheSize.c_str();
}

const char *DeviceInfo::getBaseClockFrequency(void) const {
    return baseClockFrequency.c_str();
}

const char *DeviceInfo::getMemorySize(void) const {
    return memorySize.c_str();
}

const char *DeviceInfo::getExtensions(void) const {
    return extensions.c_str();
}

const char *DeviceInfo::getMaxWorkItemsPerWorkGroup(void) const {
    return maximumWorkItemsPerWorkGroup.c_str();
}

const char *DeviceInfo::getMaxWorkGroupSize(void) const {
    return maximumWorkGroupSize.c_str();
}
